package org.snia.server.cfg;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import com.thoughtworks.xstream.converters.reflection.ObjectAccessException;
import com.thoughtworks.xstream.converters.reflection.Sun14ReflectionProvider;

/**
 * 重载XStream中默认的反射器，使用setXXX函数设置属性值，使得应用可以在setXXX中检查参数是否合法。
 * 要求在setXXX中，当校验不通过时，抛出异常IllegalArgumentException。
 * 
 */
public class FieldBySetReflectionProvider extends Sun14ReflectionProvider {

	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Override
	public void writeField(Object object, String fieldName, Object value,
			Class definedIn) {
		String setName = "set" + Character.toUpperCase(fieldName.charAt(0))
				+ fieldName.substring(1);
		try {
			Field field = fieldDictionary.field(object.getClass(), fieldName,
					definedIn);
			Class fieldType = field.getType();
			if (definedIn == null)
				definedIn = field.getDeclaringClass();

			Method setMethod;
			if (fieldType.isPrimitive()) {
				if (fieldType.equals(Integer.TYPE)) {
					setMethod = definedIn.getDeclaredMethod(setName,
							new Class[] { int.class });
				} else if (fieldType.equals(Long.TYPE)) {
					setMethod = definedIn.getDeclaredMethod(setName,
							new Class[] { long.class });
				} else if (fieldType.equals(Short.TYPE)) {
					setMethod = definedIn.getDeclaredMethod(setName,
							new Class[] { short.class });
				} else if (fieldType.equals(Character.TYPE)) {
					setMethod = definedIn.getDeclaredMethod(setName,
							new Class[] { char.class });
				} else if (fieldType.equals(Byte.TYPE)) {
					setMethod = definedIn.getDeclaredMethod(setName,
							new Class[] { byte.class });
				} else if (fieldType.equals(Float.TYPE)) {
					setMethod = definedIn.getDeclaredMethod(setName,
							new Class[] { float.class });
				} else if (fieldType.equals(Double.TYPE)) {
					setMethod = definedIn.getDeclaredMethod(setName,
							new Class[] { double.class });
				} else if (fieldType.equals(Boolean.TYPE)) {
					setMethod = definedIn.getDeclaredMethod(setName,
							new Class[] { boolean.class });
				} else {
					throw new ObjectAccessException("Could not set field "
							+ object.getClass() + "." + field.getName()
							+ ": Unknown type " + fieldType);
				}
			} else {
				setMethod = definedIn.getDeclaredMethod(setName,
						new Class[] { value.getClass() });
			}
			// 打破Java封装性，使得private函数也能调用
			setMethod.setAccessible(true);
			setMethod.invoke(object, new Object[] { value });
		} catch (InvocationTargetException e) {
			// 这里假设有效性检查通不过时系统将抛出IllegalArgumentException
			if (e.getCause() instanceof IllegalArgumentException)
				throw (IllegalArgumentException) e.getCause();
			else
				super.writeField(object, fieldName, value, definedIn);
		} catch (Exception e) {
			super.writeField(object, fieldName, value, definedIn);
		}
	}
}
